package com.sita.tboard.ui.fragment;

import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.amap.api.location.AMapLocation;
import com.amap.api.maps.AMapUtils;
import com.amap.api.maps.TextureMapView;
import com.amap.api.maps.model.LatLng;
import com.sita.bike.R;
import com.sita.bike.event.CurtainIsShownEvent;
import com.sita.bike.event.PersonalInfoUpdateEvent;
import com.sita.bike.event.SpeedActionEvent;
import com.sita.bike.model.PersonalInfo;
import com.sita.bike.model.PersonalInfoListener;
import com.sita.bike.persistence.Route;
import com.sita.bike.persistence.RouteData;
import com.sita.bike.rest.RestClient;
import com.sita.bike.rest.model.NewRankRequestParams;
import com.sita.bike.rest.model.NewRankResponse;
import com.sita.bike.support.Constants;
import com.sita.bike.support.GlobalContext;
import com.sita.bike.support.LocationController;
import com.sita.bike.ui.activity.SpeedMeterPausedActivity;
import com.sita.bike.ui.activity.roadtrust.RouteFinishStatusActivity;
import com.sita.bike.ui.fragments.MapFriendFragment;
import com.sita.bike.ui.view.NewCurtainView;
import com.sita.bike.utils.AccountUtils;
import com.sita.bike.utils.BluetoothUtils;
import com.sita.bike.utils.FormatUtils;
import com.sita.bike.utils.LogUtils;
import com.sita.bike.utils.MapUtils;
import com.sita.bike.utils.PersistUtils;
import com.sita.friend.ui.activity.PoiDestinationSearchActivity;
import com.sita.tboard.ui.activity.DashboardActivity;
import com.sita.tboard.ui.view.SpeedMeterView.SPEED_STATUS;

import app.akexorcist.bluetotohspp.library.BluetoothState;
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;

/**
 * @author lijuan zhang on 16/1/15.
 */
public class MapSpeedDashboardFragment extends MapFriendFragment {

    private static String TAG = MapSpeedDashboardFragment.class.getSimpleName();
    private static MapSpeedDashboardFragment fragment;

    private RelativeLayout mTitleBar;
    private NewCurtainView mSpeedMeterBoard;
    private TextView mTitleBarSpeed;
    private TextView mTitleBarRPM;
    private TextView mTitleBarDistance;
    private Button mSearchDestination;

    private ImageView mPowerOff;
    private ImageView mDashBoard;
    private ImageView mBlueTooth;

    private long mTrackId = 0;
    private Route mNewTrack;

    private Chronometer mChronometerTrack;
    private LatLng mLastLoc;
    private final long mGpsLoggerInterval = 1000 * 5; // 5s
    private long mGpsLoggerIntervalStart = 0;
    private LatLng _lastLoc = null;
    private float mMaxSpeed = 0;
    private int mMaxRpm = 0;
    private long mTrackTotalDistance = 0;//距离

    private long mStartTime;
    private long mEndTime;
    private boolean mIsViewCreated = false;
    private boolean isBluetoothConnected = false;
    private boolean mIsTrackAutoFinish = true;
    private double mLastTrackDistance = 0d;
    private long mLastTrackTime = 0;

    // map tracking status
    private SPEED_STATUS mSpeedStatus = SPEED_STATUS.SPEED_STATUS_READY;

    private int mSpeedBT = 0;
    private int mRpm = 0;
    private int mShift = 0;


    public static String GetTag() {
        return TAG;
    }

    public static MapSpeedDashboardFragment getInstance() {
        if (fragment == null) {
            synchronized (MapSpeedDashboardFragment.class) {
                if (fragment == null) {
                    fragment = new MapSpeedDashboardFragment();
                }
            }
        }
        return fragment;
    }

    @Override
    protected View hasCreatedView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_map_speed_dashboard, container, false);
        mapView = (TextureMapView) view.findViewById(R.id.roadmates_map);
        return view;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        mIsViewCreated = false;
        View view = super.onCreateView(inflater, container, savedInstanceState);

        mSpeedMeterBoard = (NewCurtainView) view.findViewById(R.id.curtain);
        mTitleBar = (RelativeLayout) view.findViewById(R.id.title_green);
        mTitleBarDistance = (TextView) view.findViewById(R.id.distance);
        mTitleBarSpeed = (TextView) view.findViewById(R.id.speed);
        mTitleBarRPM = (TextView) view.findViewById(R.id.run);
        mChronometerTrack = (Chronometer) view.findViewById(R.id.record_time);
        mSearchDestination = (Button) view.findViewById(R.id.btn_search_destination);

        mPowerOff = (ImageView) view.findViewById(R.id.img_power_off);
        mPowerOff.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "power off clicked");
                // stop tracking
                mSpeedStatus = SPEED_STATUS.SPEED_STATUS_READY;
                stopTrack();
                mSpeedMeterBoard.performStopTracking();

                // call the route finish activity
                Intent i = new Intent(getContext(), RouteFinishStatusActivity.class);
                Bundle bundle = new Bundle();
                bundle.putLong("trackId", mTrackId);
                bundle.putFloat("mileage", mTrackTotalDistance);
                bundle.putLong("time", mEndTime - mStartTime);

                i.putExtras(bundle);
                getContext().startActivity(i);


                // TODO: 2016/3/1
                // waiting for the activity closed, then change status to ready;
            }
        });
        mDashBoard = (ImageView) view.findViewById(R.id.img_dashboard);
        mDashBoard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getContext(), DashboardActivity.class);
                startActivity(intent);
            }
        });
        mBlueTooth = (ImageView) view.findViewById(R.id.img_blue_tooth);
        initBluetooth();
        receiveBluetoothData();
        mTitleBar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mSpeedMeterBoard.onRopeClick();
            }
        });

        mSearchDestination.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity().getApplicationContext(), PoiDestinationSearchActivity.class);
                intent.putExtra("MAP_SPEED_DASHBOARD_FRAGMENT", true);
                startActivity(intent);
            }
        });

        mSpeedMeterBoard.initMap(savedInstanceState);
        mIsViewCreated = true;
        return view;
    }

    private void setTitleBar(int speed, int rpm) {
        mTitleBarRPM.setText(String.valueOf(rpm));
        mTitleBarSpeed.setText(String.valueOf(speed));
    }

    private void setSpeedMeter(int speed, int rpm) {
        mSpeedMeterBoard.setSpeedMeterSpeed(speed);
        mSpeedMeterBoard.setSpeedMeterRpm(rpm);
    }

    public void receiveBluetoothData() {
        BluetoothUtils.registerBluetoothData(new BluetoothUtils.BluetoothDataListener() {
            @Override
            public void onDataReceived(int speed, int rpm, int shift) {
                LogUtils.i(TAG, "onDataReceived speed:" + speed + ", rpm" + rpm);
                isBluetoothConnected = true;
                mSpeedBT = speed;
                mMaxSpeed = mMaxSpeed < mSpeedBT ? mSpeedBT : mMaxSpeed;
                mRpm = rpm;
                mMaxRpm = mMaxRpm < mRpm ? mRpm : mMaxRpm;
                mShift = shift;
                if (mSpeedMeterBoard.isOpen && mSpeedStatus == SPEED_STATUS.SPEED_STATUS_RUNNING) {
                    setSpeedMeter(speed, rpm);
                } else {
                    setTitleBar(speed, rpm);
                }
            }
        });
    }

    @Override
    public void onStart() {
        if (BluetoothUtils.startBlueToothService(getActivity())) {
            BluetoothUtils.autoConnect();
        }
        super.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
        mSpeedMeterBoard.onResume();
        refreshPersonalData();
    }

    @Override
    public void onPause() {
        super.onPause();
        mSpeedMeterBoard.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onDestroy() {
        if (mSpeedMeterBoard != null) {
            mSpeedMeterBoard.onDestroy();
        }
        super.onDestroy();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        if (!hidden) {
            refreshPersonalData();
            if (mSpeedStatus == SPEED_STATUS.SPEED_STATUS_RUNNING) {
                enableScreenOn();
            }
        } else {
            disableScreenOn();
        }
    }

    private void enableScreenOn() {
        if (!GlobalContext.getWakeLock().isHeld()) {
            GlobalContext.getWakeLock().acquire();
        }
    }

    private void disableScreenOn() {
        if (GlobalContext.getWakeLock().isHeld()) {
            GlobalContext.getWakeLock().release();
        }
    }

    private void createNewTrack() {
        mNewTrack = new Route();
        mStartTime = System.currentTimeMillis();
        mNewTrack.setStartTime(mStartTime);
        mNewTrack.setStartLoc(LocationController.getLocationString());
        mNewTrack.setStartAddress(LocationController.getLocationAddress());
        mTrackId = PersistUtils.saveRoute(mNewTrack);
    }

    private void stopRecordTrack() {
        mEndTime = System.currentTimeMillis();
        mNewTrack.setEndTime(mEndTime);
        mNewTrack.setEndLoc(LocationController.getLocationString());
        mNewTrack.setEndAddress(LocationController.getLocationAddress());
        mNewTrack.setDistance(mTrackTotalDistance);
        mNewTrack.setMaxRpm(mMaxRpm);
        mNewTrack.setMaxSpeed(FormatUtils.convertSpeedToMS(mMaxSpeed));
        mNewTrack.setSyncStatus(Constants.ROUTE_FILE_SYNC_STATUS_UPLOAD_NOT);
        PersistUtils.updateRoute(mNewTrack);
    }

    @Override
    public void onLocationChanged(AMapLocation location) {
        long current = System.currentTimeMillis();
        LogUtils.d(TAG, "onLocationChanged: location provider:" + location.getProvider() +
                "; accuracy:" + location.getAccuracy());
        if (mIsViewCreated == false || mSpeedMeterBoard == null || mTitleBarSpeed == null) {
            LogUtils.d(TAG, "onLocationChanged: location discard");
            return;
        }
        LogUtils.d(TAG, "> speed=" + FormatUtils.convertSpeedToKMH(location.getSpeed()) +
                ", lat:" + location.getLatitude() +
                ", long:" + location.getLongitude());

        float speedMS = location.getSpeed();
        int speed = FormatUtils.convertSpeedToKMH(speedMS); // m/s -> km/h

        if (isBluetoothConnected) {
            speed = mSpeedBT;
            speedMS = FormatUtils.convertSpeedToMS((float) mSpeedBT);
        }

        // get max speed
        if (speed > mMaxSpeed) {
            mMaxSpeed = speed;
        }

        if (mSpeedStatus == SPEED_STATUS.SPEED_STATUS_READY ||
                mSpeedStatus == SPEED_STATUS.SPEED_STATUS_RUNNING) {

            mTitleBarSpeed.setText(String.valueOf(speed));

            if (mSpeedStatus == SPEED_STATUS.SPEED_STATUS_RUNNING) {
                Log.d(TAG, "> in status running");

                if (mSpeedMeterBoard.isOpen) {
                    if (!isBluetoothConnected) {
                        mSpeedMeterBoard.setSpeedMeterSpeed(speed);
                    }
                    mSpeedMeterBoard.setLocation(location);
                }

                drawMapLineMarker(new LatLng(location.getLatitude(), location.getLongitude()),
                        speed);

                // during running check the interval
                if (current - mGpsLoggerIntervalStart > mGpsLoggerInterval) {
                    LogUtils.d(TAG, "> location interval");
                    // reset time interval
                    mGpsLoggerIntervalStart = current;

                    // filter the gps loc
                    LatLng latLon = new LatLng(location.getLatitude(), location.getLongitude());
                    //如果是原点坐标，需要忽略
                    if (isValidGps(location.getLongitude(), location.getLatitude())) {
                        float d = 0f;
                        if (_lastLoc == null ||
                                // 两次坐标点距离>0
                                ((d = AMapUtils.calculateLineDistance(_lastLoc, latLon)) > 0) &&
                                        /*Float.compare(speed, 0f)> 0 */ true) {
                            _lastLoc = latLon;
                            LogUtils.d(TAG, "> get new location:");
                            // save the RT data
                            saveRealTimeData(location.getLatitude(), location.getLongitude(), location.getTime(),
                                    speedMS, mRpm, mShift, mTrackId);
                        }
                    }
                }
            }
        }

        if (checkTrackAutoFinish() && mSpeedStatus == SPEED_STATUS.SPEED_STATUS_RUNNING) {
            mPowerOff.performClick();
        }
        super.onLocationChanged(location);

    }

    private void displayDistance(float distance) {
        String distance_tex = FormatUtils.formatDistance2(distance);
        mTitleBarDistance.setText(distance_tex);
    }

    private void startTrack() {
        // status not set in here
        mPowerOff.setEnabled(true);
        // set gps to tracing mode;
        LocationController.startTracking(this);
        mTrackTotalDistance = 0;
        mChronometerTrack.setBase(SystemClock.elapsedRealtime());
        mChronometerTrack.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
            @Override
            public void onChronometerTick(Chronometer chronometer) {
                // update the speed meter's time value
                mSpeedMeterBoard.setSpeedMeterTime(SystemClock.elapsedRealtime() - chronometer.getBase());
            }
        });
        mChronometerTrack.start();
        createNewTrack();
        clearMap();
        resetRealTimeData();
        enableScreenOn();
        startFollowingMode();
    }

    private void stopTrack() {
        // status not set in here
        mPowerOff.setEnabled(false);
        LocationController.stopTracking(this);
        mChronometerTrack.stop();
        stopRecordTrack();
        sendNewRank();
        clearMap();
        fetchResource(); // after stop track, better to get resource again.
        resetRealTimeData();
        disableScreenOn();
        stopFollowingMode();
    }

    private void resetRealTimeData() {
        displayDistance(0f);
        mLastLoc = null;
        mMaxSpeed = 0;
        mMaxRpm = 0;
    }

    private void drawMapLineMarker(LatLng loc, float speed) {

        // filter noise locations
        if (mLastLoc != null && Float.compare(speed, 0) == 0) {
            return;
        }

        if (!isValidGps(loc.longitude, loc.latitude)) {
            return;
        }

        if (mLastLoc == null) {
            mLastLoc = loc;
        } else {
            displayDistance(mTrackTotalDistance += FormatUtils.calculateDistance(mLastLoc, loc));
            MapUtils.drawLine(mLastLoc, loc, aMap, getContext());
            mLastLoc = loc;
        }
        drawMyMarker(loc);
    }

    private void saveRealTimeData(double lat, double lon, long utc, float speed, int rpm, int shift, long trackid) {
        if (trackid > 0) {
            RouteData rtdata = new RouteData();
            rtdata.setLatitude(lat);
            rtdata.setLongitude(lon);
            rtdata.setTime(utc);
            rtdata.setSpeed(speed);
            rtdata.setRpm(rpm);
            rtdata.setShift(shift);
            rtdata.setRouteId(Integer.valueOf((int) trackid));
            PersistUtils.saveRouteData(rtdata);
        }

    }

    private static boolean isValidGps(Double longitude, Double latitude) {
        if (longitude == null || latitude == null) {
            return false;
        }
        boolean isZeroLng = Double.compare(longitude, 0) == 0;
        boolean isZeroLat = Double.compare(latitude, 0) == 0;
        return !isZeroLng && !isZeroLat;
    }

    private void sendNewRank() {
        LogUtils.i(TAG, "行驶距离" + mTrackTotalDistance + "开始时间" + mStartTime + "结束时间" + mEndTime);
        NewRankRequestParams params = new NewRankRequestParams();
        params.mAccountId = AccountUtils.getAccountID();

        if (Double.compare(mTrackTotalDistance, 0.0) == 0) {
            return;
        }

        params.mMileage = mTrackTotalDistance;
        params.mPeriod = mEndTime - mStartTime;
        RestClient.getRestNormalService().sendNewRanking(params, new Callback<NewRankResponse>() {
            @Override
            public void success(NewRankResponse newRankResponse, Response response) {
                if (response.getStatus() == 200) {
                    if (newRankResponse.mErrorCode.equals("0")) {
                        LogUtils.d(TAG, "排名发送成功");
                    }
                }
            }

            @Override
            public void failure(RetrofitError error) {
                LogUtils.d(TAG, "排名发送失败");
            }
        });
    }

    public void onEventMainThread(CurtainIsShownEvent event) {
        boolean isOpen = event.getIsOpen();
//        if (isOpen) {
//            mUiSettings.setScrollGesturesEnabled(false);
//        } else {
//            mUiSettings.setScrollGesturesEnabled(true);
//        }
    }

    public void onEventMainThread(SpeedActionEvent event) {
        int action = event.action;
        switch (action) {
            case SpeedActionEvent.ACTION_START: {
                mSpeedStatus = SPEED_STATUS.SPEED_STATUS_RUNNING;
                startTrack();
                break;
            }
            case SpeedActionEvent.ACTION_OVER: {
                // also can call by img_power_off
                mSpeedStatus = SPEED_STATUS.SPEED_STATUS_READY;
                stopTrack();
                mSpeedMeterBoard.performStopTracking();
                break;
            }
            case SpeedActionEvent.ACTION_PAUSED: {
                mSpeedStatus = SPEED_STATUS.SPEED_STATUS_PAUSED;
                // show paused activity
                Intent i = new Intent(getActivity(), SpeedMeterPausedActivity.class);
                getContext().startActivity(i);
                break;
            }

            case SpeedActionEvent.ACTION_CONTINUE: {
                mSpeedStatus = SPEED_STATUS.SPEED_STATUS_RUNNING;
                // notify the speed meter
                mSpeedMeterBoard.performContinueTracking();
                break;
            }
        }
    }

    @Override
    protected boolean canDrawRoadMatesMarker() {
        return mSpeedStatus == SPEED_STATUS.SPEED_STATUS_READY;
    }

    /*
     * Bluetooth
     */
    private void initBluetooth() {
        BluetoothUtils.initBluetooth(getActivity(), new BluetoothUtils.BluetoothServiceListener() {
            @Override
            public void onDeviceConnected() {
                setBlueToothButton(true);
            }

            @Override
            public void onDeviceDisconnected() {
                isBluetoothConnected = false;
                resetBlueToothData();
                setSpeedMeter(0, 0);
                setTitleBar(0, 0);
                setBlueToothButton(false);
            }

            @Override
            public void onDeviceConnectionFailed() {
                setBlueToothButton(false);
            }
        });

        mBlueTooth.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (BluetoothUtils.isBluetoothConnected()) {
                    BluetoothUtils.disconnect();
                } else {
                    BluetoothUtils.scanBluetoothDevice(getActivity());
                }
            }
        });
    }

    private void setBlueToothButton(boolean isBluetoothConnected) {
        if (isBluetoothConnected) {
            mBlueTooth.setImageDrawable(getResources().getDrawable(R.drawable.bluetooth_green));
        } else {
            mBlueTooth.setImageDrawable(getResources().getDrawable(R.drawable.bluetooth_white));
        }
    }

    public void handleActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == BluetoothState.REQUEST_CONNECT_DEVICE) {
            if (resultCode == Activity.RESULT_OK && data != null) {
                BluetoothUtils.connect(data);
            }
        } else if (requestCode == BluetoothState.REQUEST_ENABLE_BT) {
            if (resultCode == Activity.RESULT_OK) {
                BluetoothUtils.startService();
                if (!BluetoothUtils.autoConnect()) {
                    BluetoothUtils.scanBluetoothDevice(getActivity());
                }
            } else if (resultCode == Activity.RESULT_CANCELED) {
                // user cancel the connected, then no need to popup the prompt again.
                BluetoothUtils.setNoBluetoothPrompt();
            }
        }
    }

    private void initPersonProfileData() {
        Double mileage = AccountUtils.getMileage();
        Long total = AccountUtils.getTotalTime();
        long rank = AccountUtils.getRank();
        mSpeedMeterBoard.updatePersonaProfile(mileage, total, rank);
    }

    public void onEventMainThread(PersonalInfoUpdateEvent event) {
        mSpeedMeterBoard.updatePersonaProfile(event.mMileage, event.mTotalTime, event.mRank);
    }

    private void refreshPersonalData() {
        AccountUtils.getTrackInfoAsync(mPersonalInfoListener);
        AccountUtils.getRankingInfoAsync(mPersonalInfoListener);
    }

    private PersonalInfoListener mPersonalInfoListener = new PersonalInfoListener() {
        @Override
        public void Success(PersonalInfo info) {
            if (info.isTotal() || info.isTime()) {
                mSpeedMeterBoard.updateMileAndTime(info.getTotal(), info.getTime());
            }
            if (info.isRank()) {
                mSpeedMeterBoard.updateRank(info.getRank());
            }
        }

        @Override
        public void Failed() {

        }
    };

    private void resetBlueToothData() {
        mSpeedBT = 0;
        mRpm = 0;
        mShift = 0;
    }

    private boolean checkTrackAutoFinish() {
        if (mIsTrackAutoFinish) {
            if (mLastTrackTime == 0) {
                mLastTrackTime = System.currentTimeMillis();
            }
            // every 15 minutes, check the total distance < 100m;
            if (System.currentTimeMillis() - mLastTrackTime > 1000 * 60 * 15) {
                if (mTrackTotalDistance - mLastTrackDistance < 100) {
                    // reset data;
                    mLastTrackTime = 0;
                    mLastTrackDistance = 0d;
                    return true;
                }
                mLastTrackDistance = mTrackTotalDistance;
                mLastTrackTime = System.currentTimeMillis();
            }

        }
        return false;
    }
}
